package org.apache.ibatis.common.reflection;

import sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import sun.reflect.generics.reflectiveObjects.WildcardTypeImpl;

import java.lang.reflect.*;
import java.util.Arrays;
import java.util.List;

/**
 * @Name TypeParameterResolver
 * @Description: 类型参数解析器
 * 描述信息：解析参数化类型中参数变量的实际类型，包括成员属性、成员方法入参 & 返回值等。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-04-26 14:44:38
 **/
public class TypeParameterResolver {

    private TypeParameterResolver() {
    }

    /**
     * 解析属性的实际类型
     *
     * @param field   目标属性
     * @param srcType 目标属性所属的类
     * @return java.lang.reflect.Type 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-26 17:59:15
     */
    public static Type resolveFieldType(Field field, Type srcType) {
        // 属性类型
        Type fieldType = field.getGenericType();
        // 定义属性的类
        Class<?> declaringClass = field.getDeclaringClass();
        return resolveType(fieldType, srcType, declaringClass);
    }

    /**
     * 解析方法入参的实际类型
     *
     * @param method  目标方法
     * @param srcType 目标方法所属的类
     * @return java.lang.reflect.Type[] 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-26 18:03:18
     */
    public static Type[] resolveParamTypes(Method method, Type srcType) {
        // 取出方法的所有入参
        Type[] paramTypes = method.getGenericParameterTypes();
        // 定义目标方法的类或接口
        Class<?> declaringClass = method.getDeclaringClass();
        // 解析结果
        Type[] result = new Type[paramTypes.length];
        for (int i = 0; i < paramTypes.length; i++) {
            result[i] = resolveType(paramTypes[i], srcType, declaringClass);
        }
        return result;
    }

    /**
     * 解析返回值的实际类型
     *
     * @param method  目标方法
     * @param srcType 目标方法所属的类
     * @return java.lang.reflect.Type 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-26 14:45:23
     */
    public static Type resolveReturnType(Method method, Class<?> srcType) {
        Type returnType = method.getGenericReturnType();
        Class<?> declaringClass = method.getDeclaringClass();
        return resolveType(returnType, srcType, declaringClass);
    }

    /**
     * 解析变量的实际类型
     *
     * @param type           变量的类型
     * @param srcType        变量所属的类
     * @param declaringClass 定义变量的类或接口
     * @return java.lang.reflect.Type 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-26 14:48:24
     */
    private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
        // 1. 如果是泛型变量类型，例如 Map<K, V> 中的 "K"、"V" 就是泛型变量，Map 就是泛型变量所属的类型。
        if (type instanceof TypeVariable) return resolveTypeVariale((TypeVariable<?>) type, srcType, declaringClass);
            // 2. 如果是参数化类型，例如 Collection<String> 就是参数化类型
        else if (type instanceof ParameterizedType)
            return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
            // 3. 如果是泛型列表类型，即包含 TypeVariable 或 ParameterizedType 类型的列表
        else if (type instanceof GenericArrayType)
            return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
            // 4. 否则，不解析，返回原类型
        else return type;
    }

    /**
     * 解析泛型变量类型中的泛型变量的实际类型
     * 例如，Map<K, V>
     * - 泛型变量类型 Map
     * - 泛型变量 K、V
     *
     * @param typeVariable   泛型变量类型
     * @param srcType        变量所属的类
     * @param declaringClass 定义变量的类或接口
     * @return java.lang.reflect.Type 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-26 14:58:00
     */
    private static Type resolveTypeVariale(TypeVariable<?> typeVariable, Type srcType, Class<?> declaringClass) {
        // 泛型变量的实际类型
        Type result;
        // 泛型变量所属的类
        Class<?> clazz;
        // 1）变量属于确定的类，例如 Student<T> 中的变量 T 属于 Student 类
        if (srcType instanceof Class) clazz = (Class<?>) srcType;
            // 2）变量属于参数化类型，例如 List<String> 中的变量 String 属于 List 类
        else if (srcType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) srcType;
            clazz = (Class<?>) parameterizedType.getRawType();
        }
        // 3）否则，解析失败
        else {
            String msg = "第二个参数必须是 Class 或者 ParameterizedType 类型，但传入的是：" + srcType.getClass();
            throw new IllegalArgumentException(msg);
        }
        // 1. 如果变量所属的类和定义变量的类一致，例如 public class User<T> { private Student<T> stu }，变量 T 属于 Student，但定义于 User
        if (clazz == declaringClass) {
            // 返回变量的上界
            Type[] bounds = typeVariable.getBounds();
            if (bounds.length > 0) return bounds[0];
            return Object.class;
        }

        // 2. 如果变量所属的类和定义变量的类不一致，则获取变量属于的类的父类，并扫描父类，查看能否确定上界。例如，变量 T 属于 Student，其父类为 User<Number>，上界为 Number
        Type superClass = clazz.getGenericSuperclass();
        result = scanSupperTypes(typeVariable, srcType, declaringClass, clazz, superClass);
        if (result != null) return result;

        return null;
    }

    private static Type scanSupperTypes(TypeVariable<?> typeVariable, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superClass) {
        // 1. 如果父类为参数化类型
        if (superClass instanceof ParameterizedType) {
            // 父类类型
            ParameterizedType parentAsType = (ParameterizedType) superClass;
            // 父类
            Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
            // 父类中的类型变量
            TypeVariable<?>[] parentTypeVariables = parentAsClass.getTypeParameters();
            if (srcType instanceof ParameterizedType) {
                // 如果变量所属的类为参数化类型，转换父类类型
                parentAsType = translateParentTypeVariables((ParameterizedType) srcType, clazz, parentAsType);
            }
            // 如果子类和父类一致
            if (declaringClass == parentAsClass) {
                for (int i = 0; i < parentTypeVariables.length; i++) {
                    if (typeVariable == parentTypeVariables[i]) {
                        // 返回父类中的类型变量的实际类型
                        return parentAsType.getActualTypeArguments()[i];
                    }
                }
            }
            // 如果子类派生于父类
            if (declaringClass.isAssignableFrom(parentAsClass)) {
                // 递归解析变量的实际类型
                return resolveTypeVariale(typeVariable, parentAsType, declaringClass);
            }
        }
        // 2. 如果父类为 Class 类型，且父类就是定义变量的类
        else if (superClass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superClass)) {
            // 递归解析变量的实际类型
            return resolveTypeVariale(typeVariable, superClass, declaringClass);
        }
        return null;
    }

    private static ParameterizedType translateParentTypeVariables(ParameterizedType srcType, Class<?> srcClass, ParameterizedType parentAsType) {
        Type[] parentTypeArgs = parentAsType.getActualTypeArguments();
        Type[] srcTypeArgs = srcType.getActualTypeArguments();
        TypeVariable<?>[] srcTypeVariables = srcClass.getTypeParameters();
        Type[] newParentArgs = new Type[parentTypeArgs.length];
        boolean noChange = true;
        for (int i = 0; i < parentTypeArgs.length; i++) {
            if (parentTypeArgs[i] instanceof TypeVariable) {
                for (int j = 0; j < srcTypeVariables.length; j++) {
                    if (srcTypeArgs[j] == parentTypeArgs[i]) {
                        noChange = false;
                        newParentArgs[i] = srcTypeArgs[j];
                    }
                }
            } else {
                newParentArgs[i] = parentTypeArgs[i];
            }
        }
        return noChange ? parentAsType : new ParameterizedTypeImpl((Class<?>) parentAsType.getRawType(), null, newParentArgs);
    }

    /**
     * 解析参数化类型中的变量的实际类型
     * 例如，List<T>
     * - 参数化类型 List
     * - 类型参数变量 T
     *
     * @param parameterizedType 参数化类型中的变量
     * @param srcType           变量所属的类
     * @param declaringClass    定义变量的类或接口
     * @return java.lang.reflect.Type 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-26 15:52:14
     */
    private static Type resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
        // 参数化类型 List
        Class<?> rawType = (Class<?>) parameterizedType.getRawType();
        // 类型参数 T
        Type[] typeArgs = parameterizedType.getActualTypeArguments();
        // 类型参数 T 的实际类型
        Type[] args = new Type[typeArgs.length];
        for (int i = 0; i < typeArgs.length; i++) {
            // 1. 如果类型参数是类型变量，例如 List<T> 中的 T
            if (typeArgs[i] instanceof TypeVariable)
                args[i] = resolveTypeVariale((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
                // 2. 如果类型参数是参数化类型，例如 List<List<T>> 中的 List<T>
            else if (typeArgs[i] instanceof ParameterizedType)
                args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
                // 3. 如果类型参数是通配符类型，例如 List<? extends Number> 中的 ?
            else if (typeArgs[i] instanceof WildcardType)
                args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
                // 4. 否则，参数是确定的类型，例如 List<String> 中的 String
            else args[i] = typeArgs[i];
        }
        return new ParameterizedTypeImpl(rawType, null, args);
    }

    /**
     * 解析通配符类型中的变量的实际类型
     * 例如，List<? extend | super Number>
     * - 通配符类型 List
     * - 类型参数变量 ?
     *
     * @param wildcardType   通配符类型中的变量
     * @param srcType        变量所属的类
     * @param declaringClass 定义变量的类或接口
     * @return java.lang.reflect.Type 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-26 17:29:03
     */
    private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
        // 解析通配符类型的下界，例如 List<? super Student> 通配符类型的下界为 Student 类
        Type[] lowerBounds = resolveWildcardTypeBounds(wildcardType.getLowerBounds(), srcType, declaringClass);
        // 解析通配符类型的上界，例如 List<? extend Number> 通配符类型的上界为 Number 类
        Type[] upperBounds = resolveWildcardTypeBounds(wildcardType.getUpperBounds(), srcType, declaringClass);
        // 返回结果
        return new WildcardTypeImpl(lowerBounds, upperBounds);
    }

    private static Type[] resolveWildcardTypeBounds(Type[] bounds, Type srcType, Class<?> declaringClass) {
        Type[] result = new Type[bounds.length];
        for (int i = 0; i < bounds.length; i++) {
            if (bounds[i] instanceof TypeVariable)
                result[i] = resolveTypeVariale((TypeVariable<?>) bounds[i], srcType, declaringClass);
            else if (bounds[i] instanceof ParameterizedType)
                result[i] = resolveParameterizedType((ParameterizedType) bounds[i], srcType, declaringClass);
            else if (bounds[i] instanceof WildcardType)
                result[i] = resolveWildcardType((WildcardType) bounds[i], srcType, declaringClass);
            else
                result[i] = bounds[i];
        }
        return result;
    }

    /**
     * 解析泛型列表中的变量的实际类型
     *
     * @param genericArrayType 泛型列表中的变量类型
     * @param srcType          变量所属的类
     * @param declaringClass   定义变量的类或接口
     * @return java.lang.reflect.Type 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-26 17:45:39
     */
    private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) {
        // 泛型列表类型
        Type componentType = genericArrayType.getGenericComponentType();
        // 泛型列表的实际类型
        Type resolvedComponentType = null;
        if (componentType instanceof TypeVariable)
            // 如果是泛型变量类型，例如 T[]
            resolvedComponentType = resolveTypeVariale((TypeVariable<?>) componentType, srcType, declaringClass);
        else if (componentType instanceof ParameterizedType)
            // 如果是参数化类型，例如 Collection<T>[]
            resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
        else if (componentType instanceof GenericArrayType)
            // 如果是泛型列表类型，例如 T[][]
            resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
        // 返回结果
        if (resolvedComponentType instanceof Class)
            return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
        else
            return new GenericArrayTypeImpl(resolvedComponentType);
    }

    /**
     * 参数化类型
     * 例如，Map<String, Object>
     * - 参数化类型 Map
     * - 参数类型 String、Object
     *
     * @author lichao
     * @version v1.0.0
     * @date 2024-04-26 15:42:47
     */
    static class ParameterizedTypeImpl implements ParameterizedType {
        // 声明此类型的类或接口的 Type 对象
        private Class<?> rawType;
        // 参数化类型 Map
        private Type ownerType;
        // 参数类型 String、Object
        private Type[] actualTypeArguments;

        public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
            super();
            this.rawType = rawType;
            this.ownerType = ownerType;
            this.actualTypeArguments = actualTypeArguments;
        }

        @Override
        public Type[] getActualTypeArguments() {
            return actualTypeArguments;
        }

        @Override
        public Type getRawType() {
            return rawType;
        }

        @Override
        public Type getOwnerType() {
            return ownerType;
        }

        @Override
        public String toString() {
            return "ParameterizedTypeImpl{" +
                    "rawType=" + rawType +
                    ", ownerType=" + ownerType +
                    ", actualTypeArguments=" + Arrays.toString(actualTypeArguments) +
                    '}';
        }
    }

    /**
     * 通配符类型中的参数变量所属上下界的实际类型
     * 例如，对于通配符类型 List<? extend | super Number>
     * - List<? extend Number> 上界类型 Number
     * - List<? super Number> 下界类型 Number
     *
     * @author lichao
     * @version v1.0.0
     * @date 2024-04-26 17:40:47
     */
    static class WildcardTypeImpl implements WildcardType {
        private Type[] lowerBounds;
        private Type[] upperBounds;

        public WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
            super();
            this.lowerBounds = lowerBounds;
            this.upperBounds = upperBounds;
        }

        @Override
        public Type[] getUpperBounds() {
            return upperBounds;
        }

        @Override
        public Type[] getLowerBounds() {
            return lowerBounds;
        }
    }

    /**
     * 泛型列表类型
     *
     * @author lichao
     * @version v1.0.0
     * @date 2024-04-26 17:55:12
     */
    static class GenericArrayTypeImpl implements GenericArrayType {
        private Type genericComponentType;

        public GenericArrayTypeImpl(Type genericComponentType) {
            super();
            this.genericComponentType = genericComponentType;
        }

        @Override
        public Type getGenericComponentType() {
            return genericComponentType;
        }
    }

}

